package net.alteiar.plateform.game.model;

import net.alteiar.plateform.game.GUID;
import net.alteiar.plateform.game.Rectangle2D;
import net.alteiar.plateform.game.Vector2D;

/**
 * An entity represents any element that appears in the game. The entity is
 * responsible for resolving collisions and movement based on a set of
 * properties defined either by subclass or externally.
 * 
 * Note that doubles are used for positions. This may seem strange given that
 * pixels locations are integers. However, using double means that an entity can
 * move a partial pixel. It doesn't of course mean that they will be display
 * half way through a pixel but allows us not lose accuracy as we move.
 * 
 * @author Kevin Glass
 * @author Cody Stoutenburg
 */
public abstract class Entity extends GUID implements EntityModel {
	/** The current speed of this entity vertically (pixels/sec) */
	private Vector2D currentSpeed;

	private final Double maxSqrSpeed;

	/** The rectangle used for this entity during collisions resolution */
	private final Rectangle2D location;

	/**
	 * Construct a entity based on a sprites image and a location.
	 * 
	 * @param ref
	 *            The reference to the image to be displayed for this entity
	 * @param x
	 *            The initial x location of this entity
	 * @param y
	 *            The initial y location of this entity
	 */
	public Entity(double x, double y, double width, double height,
			double maxSpeed) {
		this.currentSpeed = new Vector2D(0.0, 0.0);
		this.maxSqrSpeed = Math.pow(maxSpeed, 2);

		this.location = new Rectangle2D(x, y, width, height);
	}

	/**
	 * Request that this entity move itself based on a certain ammount of time
	 * passing.
	 * 
	 * @param delta
	 *            The ammount of time that has passed in milliseconds
	 */
	public void move(long timeMs) {
		double x = this.location.getX();
		double y = this.location.getY();

		// update the location of the entity based on move speeds
		x += (timeMs * currentSpeed.getX()) / 1000.0;
		y += (timeMs * currentSpeed.getY()) / 1000.0;

		this.location.setLocation(x, y);
	}

	/**
	 * Set the speed of this entity
	 * 
	 * @param dx
	 *            The speed of this entity (meter/sec)
	 */
	public Boolean setSpeed(Vector2D newSpeed) {
		Boolean isChanged = false;
		if (newSpeed.getSquaredMagnitude() < maxSqrSpeed) {
			this.currentSpeed = newSpeed;
			isChanged = true;
		}
		return isChanged;
	}

	@Override
	public Vector2D getCurrentSpeed() {
		return this.currentSpeed;
	}

	@Override
	public Double getRelativeSpeed() {
		return this.currentSpeed.getMagnitude() / this.maxSqrSpeed;
	}

	/**
	 * Do the logic associated with this entity. This method will be called
	 * periodically based on game events
	 */
	public void doLogic() {
	}

	/**
	 * Get the x location of this entity
	 * 
	 * @return The x location of this entity
	 */
	@Override
	public Double getX() {
		return this.location.getX();
	}

	/**
	 * Get the y location of this entity
	 * 
	 * @return The y location of this entity
	 */
	@Override
	public Double getY() {
		return this.location.getY();
	}

	public Rectangle2D getRectangle() {
		return this.location;
	}

	/**
	 * Check if this entity collided with another.
	 * 
	 * @param other
	 *            The other entity to check collision against
	 * @return True if the entities collide with each other
	 */
	public boolean checkCollisionWith(Entity other) {
		return location.intersects(other.getRectangle());
	}

	/**
	 * Notification that this entity collided with another.
	 * 
	 * @param other
	 *            The entity with which this entity collided.
	 */
	public abstract void collidedWith(Entity other);

	public abstract void outOfWorld();
}
